package com.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.config.AliPayConfig;
import com.constant.AccountChangeDirectionConstant;
import com.constant.AccountChangeTypeConstant;
import com.constant.AgentAlipaySettleWayConstant;
import com.constant.BussinessResultCodeEnum;
import com.dao.*;
import com.exception.BusinessException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.model.*;
import com.page.GenericPage;
import com.service.SettleService;
import com.utils.CurrentLoginUserAgent;
import com.utils.DateUtil;
import com.utils.RandomUtils;
import com.utils.SessionUtil;
import com.vo.AgentAccountVO;
import com.vo.SettleVO;
import com.vo.WholeDailySaleVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.testng.collections.Lists;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

/**
 * @Author: chihaojie
 * @Date: 2019/8/3 13:44
 * @Version 1.0
 * @Note
 */

@Repository
public class SettleServiceImpl implements SettleService {


    @Autowired
    private SettleMapper settleMapper;


    @Autowired
    private AgentAlipayAccountMapper agentAlipayAccountMapper;

    @Autowired
    private AgentAccountMapper agentAccountMapper;

    @Autowired
    private PlatformAccountMapper platformAccountMapper;

    @Autowired
    private  AlipayFundTransferResponseLogMapper  transferResponseLogMapper;


    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private StatisticMapper statisticMapper;



    @Autowired
    private  AccountChangeFlowMapper  accountChangeFlowMapper;



    @Override
    public void handleAgentSettleOrder() {
        //查询所有的代理商账号
        //生成会计日期
        //判断未结算单里有没有该代理商的未结算记录
        //如果没有，则生成
        //生成结算单：
        //1、查询该代理商上月的订单收入
        //2、和总订单数
        //如果有则不处理
        //获取第一个工作日的时间
        Date firstWorkDay = DateUtil.getTheFirstWorkDayOfMonth(new Date());
        //获取本月第一天的时间
        Date firstDayMorning = DateUtil.getFirstDayMorningOfMonth();
        //有哪些是第一个工作日的代理商
        //有哪些是月首天的代理商
        //查询结算方式的代理商id
        List<Long> workDayUserIdList = agentAlipayAccountMapper.selectAgentIdListBySettleWay(AgentAlipaySettleWayConstant.WORK_DAY);
        List<Long> firstDayUserIdList = agentAlipayAccountMapper.selectAgentIdListBySettleWay(AgentAlipaySettleWayConstant.MONTH_FIRST_DAY);

        //处理工作日结算的
        Date now = new Date();
        Date currentDateMoring = DateUtil.getMorning(now);
        Date workDay = DateUtil.getTheFirstWorkDayOfMonth(now);
        String lastMonth = DateUtil.getLastMonth();
        //分情况处理
        if (currentDateMoring.getTime() == workDay.getTime() && !ObjectUtils.isEmpty(workDayUserIdList)) {
            //工作日
            for (Long userId : workDayUserIdList) {
                try {
                    generateSettlementOrderForAgent(userId, lastMonth);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        //月首天
        if (!ObjectUtils.isEmpty(firstDayUserIdList) && currentDateMoring.getTime() == firstDayMorning.getTime()) {
            for (Long userId : workDayUserIdList) {
                generateSettlementOrderForAgent(userId, lastMonth);
            }
        }

    }

    public void generateSettlementOrderForAgent(Long id, String lastMonth) {
        Date now = new Date();
        //判断未结算单里有没有该代理商的未结算记录
        //如果没有，则生成
        //生成结算单：
        //1、查询该代理商上月的订单收入
        //2、和总订单数
        //如果有则不处理
        AgentAlipayAccount alipayAccount = agentAlipayAccountMapper.selectByAgentId(id);
        Settle settle = settleMapper.selectByAgentAndWorkDate(id, lastMonth);
        if (ObjectUtils.isEmpty(settle)) {
            //查询该代理商已支付租赁订单和售卖订单的总金额
            Date lastMonthDate = DateUtil.addMonth(DateUtil.getFirstDayMorningOfMonth(new Date()), -1);
            Date firstDayMorningOfMonth = DateUtil.getFirstDayMorningOfMonth(lastMonthDate);
            Date firstDayMorningOfNextMonth = DateUtil.getFirstDayMorningOfNextMonth(lastMonthDate);
            WholeDailySaleVO saleVO = statisticMapper.selectAgentSaleStatisticByStarttimeAndEndtime(id + "", firstDayMorningOfMonth, firstDayMorningOfNextMonth);
            if(saleVO.getSaleMoney()>0.00){
                //查询代理商的财务账户
                AgentAccount agentAccount = agentAccountMapper.selectByAgentId(id);
                Settle unsettle = new Settle();
                String randomString = RandomUtils.randomString(5);
                String currTime = DateUtil.getCurrTime();
                unsettle.setSettleOrderNum(currTime + randomString);
                unsettle.setAccountId(agentAccount.getId());
                unsettle.setAccountName(agentAccount.getAccountName());
                unsettle.setWorkDate(lastMonth);
                unsettle.setAskTime(now);
                unsettle.setSettleAmount(new BigDecimal(saleVO.getSaleMoney()));
                unsettle.setSettleOrderNum(saleVO.getSaleNum() + "");
                unsettle.setSettleChannel(2);
                unsettle.setSettleWay(alipayAccount.getSettleWay());
                unsettle.setPayee(alipayAccount.getAliAccount());
                unsettle.setPayeeName(alipayAccount.getAliAccountName());
                unsettle.setSettleStatus(0);
                unsettle.setStatusComment("未结算");
                unsettle.setCreateTime(now);
                settleMapper.insert(unsettle);
            }

        }
        return;
    }


    @Override
    public GenericPage<SettleVO> queryUnSettledPage(Long agent, Integer settleWay, Integer pageNo, Integer pageSize) {
        handleAgentSettleOrder();
        List<SettleVO> settleVOList = Lists.newArrayList();
        Settle condition = new Settle();
        condition.setAccountId(agent);
        condition.setSettleStatus(0);
        condition.setSettleWay(settleWay);
        //未结算
        PageInfo<SettleVO> pageInfo = PageHelper.startPage(pageNo, pageSize).doSelectPageInfo(() -> {
            List<Settle> list = settleMapper.selectByCondition(condition);
            Optional.ofNullable(list).ifPresent(f -> {
                for (Settle s : list) {
                    SettleVO vo = new SettleVO();
                    BeanUtils.copyProperties(s, vo);
                    settleVOList.add(vo);
                }
            });
        });
        GenericPage<SettleVO> genericPage = new GenericPage<SettleVO>(pageSize, pageInfo.getTotal(), settleVOList);
        return genericPage;
    }

    @Override
    public GenericPage<SettleVO> querySettleHistoryPage(Long agent, Integer way, Integer settleStatus, Integer pageNo, Integer pageSize) {
        List<SettleVO> settleVOList = Lists.newArrayList();
        Settle condition = new Settle();
        condition.setAccountId(agent);
        condition.setSettleStatus(settleStatus);
        condition.setSettleWay(way);
        //未结算
        PageInfo<SettleVO> pageInfo = PageHelper.startPage(pageNo, pageSize).doSelectPageInfo(() -> {
            List<Settle> list = settleMapper.selectByConditionAlreadySettled(condition);
            Optional.ofNullable(list).ifPresent(f -> {
                for (Settle s : list) {
                    SettleVO vo = new SettleVO();
                    BeanUtils.copyProperties(s, vo);
                    settleVOList.add(vo);
                }
            });
        });
        GenericPage<SettleVO> genericPage = new GenericPage<SettleVO>(pageSize, pageInfo.getTotal(), settleVOList);
        return genericPage;
    }

    @Override
    public GenericPage<SettleVO> queryMineSettledHistoryPage(Integer pageNo, Integer pageSize) {
        Long businessId = CurrentLoginUserAgent.getBusinessId();
        SysUser user = CurrentLoginUserAgent.getUser();
        List<SettleVO> settleVOList = Lists.newArrayList();
        Settle condition = new Settle();
        if(user.getUserType().equals(2)){
            AgentAccount agentAccount = agentAccountMapper.selectByAgentId(businessId);
            condition.setAccountId(agentAccount.getId());
            condition.setSettleStatus(1);
        }else {
            condition.setSettleStatus(1);
        }
        //已结算
        PageInfo<SettleVO> pageInfo = PageHelper.startPage(pageNo, pageSize).doSelectPageInfo(() -> {
            List<Settle> list = settleMapper.selectByCondition(condition);
            Optional.ofNullable(list).ifPresent(f -> {
                for (Settle s : list) {
                    SettleVO vo = new SettleVO();
                    BeanUtils.copyProperties(s, vo);
                    settleVOList.add(vo);
                }
            });
        });
        GenericPage<SettleVO> genericPage = new GenericPage<SettleVO>(pageSize, pageInfo.getTotal(), settleVOList);
        return genericPage;
    }

    @Override
    public List<AgentAccountVO> queryAgentList() {
        List<AgentAccountVO>  list=Lists.newArrayList();
        AgentAccount condition=new AgentAccount();
        List<AgentAccount> agentAccountList= agentAccountMapper.selectByCondition(condition);
        Optional.ofNullable(agentAccountList).ifPresent(e->{
            for (AgentAccount u: agentAccountList) {
                AgentAccountVO  vo=new AgentAccountVO();
                BeanUtils.copyProperties(u,vo);
                list.add(vo);
            }
        });
        return list;
    }

    @Transactional
    @Override
    public Boolean settle(Long id) {
        Long businessId = CurrentLoginUserAgent.getBusinessId();
        Integer currentUserType = SessionUtil.getCurrentUserType();
        Date  now=new Date();
        if(!currentUserType.equals(1)){
            throw new BusinessException("权限不足！！！");
        }
        Settle settle = settleMapper.selectByPrimaryKey(id);
        if(ObjectUtils.isEmpty(settle)){
            throw new BusinessException("没有对应的结算单");
        }
        AgentAccount agentAccount =  agentAccountMapper.selectByPrimaryKey(settle.getAccountId());
        if(ObjectUtils.isEmpty(agentAccount)){
            throw  new BusinessException(BussinessResultCodeEnum.AGENT_ACCOUNT_NOT_EXIST);
        }
        BigDecimal balanceAmount = agentAccount.getBalanceAmount();
        if(balanceAmount.subtract(settle.getSettleAmount()).doubleValue()<0){
            throw  new BusinessException(BussinessResultCodeEnum.AGENT_ACCOUNT_BALANCE_INSUFFICIENT);
        }
        //判断订单状态
        if(settle.getSettleStatus().equals(2)){
            throw new BusinessException("不可重复结算");
        }
        try{
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", AliPayConfig.ONLINE_APP_ID, AliPayConfig.ONLINE_APP_PRIVATE_KEY, "json", "GBK", AliPayConfig.ONLINE_PUBLIC_KEY, "RSA2");
            AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
            AlipayFundTransToaccountTransferModel  model=new AlipayFundTransToaccountTransferModel();
            model.setOutBizNo(settle.getSettleOrderNum());
            model.setPayeeType("ALIPAY_LOGONID");
            model.setPayeeAccount(settle.getPayee());
            model.setAmount(settle.getSettleAmount().toString());
            model.setPayerShowName("测试转账");
            model.setRemark("代理商上月收入结算");
            request.setBizModel(model);
            AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
            AlipayFundTransferResponseLog  log=new AlipayFundTransferResponseLog();
            log.setSettleOrderNum(response.getOutBizNo());
            log.setCode(response.getCode());
            log.setMsg(response.getMsg());
            log.setHappenTime(now);
            log.setFullResponse(JSONObject.toJSONString(log));
            log.setCreateTime(now);
            CompletableFuture.runAsync(()->{transferResponseLogMapper.insert(log);});
            if(response.isSuccess()){
                settle.setThirdTradeNum(response.getOrderId());
                settle.setSettleTime(DateUtil.parse(response.getPayDate()));
                settle.setSettleStatus(1);
            } else {
                settle.setFailMsg(response.getSubMsg());
                settle.setSettleStatus(2);
            }
        }catch (Exception e){
           throw new BusinessException("支付宝转账调用失败！！！");
        }
        settle.setOperatorId(1L);
        settle.setOperatorName("root");
        settleMapper.updateByPrimaryKey(settle);
        //生成账务数据
        PlatformAccount platformAccount = platformAccountMapper.selectByPrimaryKey(1L);
        BigDecimal platformOutgo =platformAccount.getOutgoAmount().add(settle.getSettleAmount());
        BigDecimal platformBalance = platformAccount.getBalanceAmount().subtract(settle.getSettleAmount());
        BigDecimal lastTermBalanceAmount = platformAccount.getBalanceAmount();
        platformAccount.setOutgoAmount(platformOutgo);
        platformAccount.setBalanceAmount(platformBalance);
        platformAccount.setLastTermBalance(lastTermBalanceAmount);
        platformAccount.setUpdateTime(now);
        //生成变动流水
        AccountChangeFlow platformAccountChangeFlow=new AccountChangeFlow();
        platformAccountChangeFlow.setAccountId(platformAccount.getId());
        platformAccountChangeFlow.setAccountName(platformAccount.getAccountName());
        platformAccountChangeFlow.setAccountType(1);
        platformAccountChangeFlow.setChangeType(AccountChangeTypeConstant.platformBalaceAccountOutgo);
        platformAccountChangeFlow.setChangeTypeName("平台每月为代理商结算");
        platformAccountChangeFlow.setChangeDirection(AccountChangeDirectionConstant.OUTGO);
        platformAccountChangeFlow.setBeforeChangeAmount(lastTermBalanceAmount);
        platformAccountChangeFlow.setChangeAmount(settle.getSettleAmount());
        platformAccountChangeFlow.setAfterChangeAmount(platformAccount.getBalanceAmount());
        platformAccountChangeFlow.setRelationOrderNum(settle.getSettleOrderNum());
        platformAccountChangeFlow.setCreateTime(now);
        //代理商财务数据变动
        //代理商账户余额减少
        BigDecimal  currentBalance=balanceAmount.subtract(settle.getSettleAmount());
        BigDecimal currentSettledAmount = agentAccount.getSettledAmount().add(settle.getSettleAmount());
        agentAccount.setBalanceAmount(currentBalance);
        agentAccount.setSettledAmount(currentSettledAmount);
        agentAccount.setLastTermBalance(agentAccount.getBalanceAmount());
        agentAccount.setUpdateTime(now);
        agentAccount.setUpdated("root");
        //代理商财务变动流水
        AccountChangeFlow agentAccountChangeFlow=new AccountChangeFlow();
        agentAccountChangeFlow.setAccountId(agentAccount.getId());
        agentAccountChangeFlow.setAccountName(agentAccount.getAccountName());
        agentAccountChangeFlow.setAccountType(2);
        agentAccountChangeFlow.setChangeType(AccountChangeTypeConstant.agentBalaceAccountIncome);
        agentAccountChangeFlow.setChangeTypeName("代理商上月收入结算");
        agentAccountChangeFlow.setChangeDirection(AccountChangeDirectionConstant.OUTGO);
        agentAccountChangeFlow.setBeforeChangeAmount(balanceAmount);
        agentAccountChangeFlow.setChangeAmount(settle.getSettleAmount());
        agentAccountChangeFlow.setAfterChangeAmount(agentAccount.getBalanceAmount());
        agentAccountChangeFlow.setCreateTime(now);
        platformAccountMapper.updateByPrimaryKey(platformAccount);
        accountChangeFlowMapper.insert(platformAccountChangeFlow);
        agentAccountMapper.updateByPrimaryKey(agentAccount);
        accountChangeFlowMapper.insert(agentAccountChangeFlow);
        return true;
    }

    @Override
    public AgentAccountVO queryFinanceAccount() {
        AgentAccountVO  agentAccountVO=new AgentAccountVO();
        Long businessId = CurrentLoginUserAgent.getBusinessId();
        Integer currentUserType = SessionUtil.getCurrentUserType();
        if(currentUserType.equals(1)){
            PlatformAccount platformAccount = platformAccountMapper.selectByPrimaryKey(1L);
            agentAccountVO.setAmount(platformAccount.getIncomeAmount());
            agentAccountVO.setBalanceAmount(platformAccount.getBalanceAmount());
            agentAccountVO.setSettledAmount(platformAccount.getOutgoAmount());
            agentAccountVO.setLastTermBalance(platformAccount.getLastTermBalance());
        }else {
            AgentAccount agentAccount = agentAccountMapper.selectByAgentId(businessId);
            Optional.ofNullable(agentAccount).ifPresent((e)->{
                BeanUtils.copyProperties(e,agentAccountVO);
            });
        }
        return agentAccountVO;
    }
}
